/*
 * MIT License
 *
 * Copyright (c) 2023-present, tangli
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package tony.crypto.symmetric

import java.security.Security
import javax.crypto.Cipher
import javax.crypto.spec.SecretKeySpec
import tony.crypto.bouncyCastleProvider

/**
 * SM4 国密对称加密单例类
 *
 * SM4 是中华人民共和国政府采用的一种分组密码标准，
 * 用于无线局域网产品的安全性与互操作性测试。
 * 该算法采用 128 位密钥长度，分组长度为 128 位。
 *
 * @author tangli
 * @date 2025/01/22 14:30
 */
internal data object Sm4 : SymmetricCrypto {
    /**
     * SM4 密钥长度（字节）
     */
    private const val KEY_SIZE = 16

    /**
     * SM4 加密算法标识
     */
    private const val SM4 = "SM4"

    /**
     * SM4 加密模式：ECB 模式 + PKCS7Padding
     */
    private const val CIPHER_ALGORITHM = "SM4/ECB/PKCS7Padding"

    init {
        Security.addProvider(bouncyCastleProvider)
    }

    /**
     * SM4 对称加密解密核心方法
     *
     * @param [src] 待加密/解密的字节数组
     * @param [secret] SM4 密钥，必须为 16 字节（128 位）
     * @param [mode] 加密/解密模式 [Cipher.ENCRYPT_MODE]/[Cipher.DECRYPT_MODE]
     * @return [ByteArray] 加密/解密后的字节数组
     * @throws IllegalArgumentException 当密钥长度不为 16 字节时抛出
     * @author tangli
     * @date 2025/01/22 14:30
     */
    public override fun crypto(
        src: ByteArray,
        secret: ByteArray,
        mode: Int,
    ): ByteArray {
        require(secret.size == KEY_SIZE) { "IllegalSm4Key, sm4Key's length must be $KEY_SIZE" }
        val secretKeySpec = SecretKeySpec(secret, SM4)
        return Cipher
            .getInstance(CIPHER_ALGORITHM, "BC")
            .apply {
                init(mode, secretKeySpec)
            }.doFinal(src)
    }
}
